package com.cskaoyan.javase.oop2.encapsulate._2polymorphic._2advantage;


/**
 * 多态是面向对象三大特征之一
 * 它基于继承而实现，是面向对象思想的集大成者。接下来我们研究一下，它的优缺点。
 *
 * 我们通过一个案例：
 *  科学家要收集动物的叫声去研究
 *  先要收集猫，狗两种动物的叫声研究。随后又扩展到其它动物，最后又需要研究人类。
 *
 *  多态的优点:
 *  1.要实现多态必须要继承，而继承提高了代码复用率，提升了程序的可维护性。（继承保证）
 *
 *  2.有了多态后，用父类引用指向不同子类对象，只需要调用同名方法，就能自动根据不同子类对象，得出不同的行为。这大幅度简化了代码，提升了程序的扩展性。（多态保证）
 *
 * 多态的缺点:
 * 使用父类引用指向子类对象时
 * 父类的引用会限制访问范围仅父类
 * 这时是无法直接访问子类独有成员的
 *
 * 既然有这个缺点,那就考虑解决它?
 * 考虑进行引用数据类型的强制类型转换,也就是向下转型
 *
 * @since 11:07
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        // collectCatVoice(new Cat());
        collectAnimalVoice(new Dog());
        collectAnimalVoice(new Cat());
        collectAnimalVoice(new Pig());
        collectAnimalVoice(new Person());
    }

    // 写一个方法,收集研究所有的动物的叫声,这时仅需要传入一个Animal类的子类对象就可以了
    public static void collectAnimalVoice(Animal a) {

        // 如果传入的人的对象,就需要先执行加钱方法,需要进行强转
        // 为了这个强转只有在方法传入Person对象时进行,使用instanceof关键字判断
        if (a instanceof Person) {
            ((Person) a).addMoney();
        }

        // 调用方法,让这个动物叫,然后收集研究
        a.shout();
    }

    /*// 写一个方法,收集研究猫的叫声,该方法需要传入一个猫的对象
    public static void collectCatVoice(Cat c){
        // 调用方法,让猫叫,然后收集研究
        c.shout();
    }*/
}

class Animal {
    // 共同的属性
    public void shout() {
        System.out.println("动物发出了叫声!");
    }
}

class Cat extends Animal {
    @Override
    public void shout() {
        System.out.println("喵喵喵~");
    }
}

class Dog extends Animal {
    @Override
    public void shout() {
        System.out.println("旺旺旺~");
    }
}

class Pig extends Animal {
    @Override
    public void shout() {
        System.out.println("笑出了猪叫!");
    }
}

class Person extends Animal {

    // 但是人毕竟不能像动物一样,抓过来,人是需要请过来的,要像让人叫,得加钱
    // Person类有独特的行为: 加钱的行为
    public void addMoney() {
        System.out.println("这种事情我很办,得加钱!给钱就叫!");
    }

    @Override
    public void shout() {
        System.out.println("你干嘛~ 嘤嘤嘤");
    }
}